Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\runtime\src\message\interface.rs
Line
Count
Source
1
// Copyright (c) 2025, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use bp3d_util::simple_error;
30
31
simple_error! {
32
    pub Error {
33
        InvalidUtf8 => "invalid UTF-8 string",
34
        Truncated => "truncated input",
35
        InvalidUnionDiscriminant(usize) => "invalid union discriminant ({})",
36
        (impl From) Io(std::io::Error) => "io error: {}"
37
    }
38
}
39
40
pub type Result<T> = std::result::Result<T, Error>;
41
42
#[derive(Default, Copy, Clone, Debug)]
43
pub struct FieldOffset {
44
    pub start: usize,
45
    pub end: usize,
46
}
47
48
impl FieldOffset {
49
6
    pub fn size(&self) -> usize {
50
6
        self.end - self.start
51
6
    }
52
}
53
54
pub struct Message<T> {
55
    data: T,
56
    size: usize,
57
}
58
59
impl<T> Message<T> {
60
530
    pub fn new(size: usize, data: T) -> Self {
61
530
        Self { data, size }
62
530
    }
63
64
514
    pub fn into_inner(self) -> T {
65
514
        self.data
66
514
    }
67
68
    /// Access the underlying parts of this message.
69
0
    pub fn into_parts(self) -> (T, usize) { (self.data, self.size) }
70
71
518
    pub fn size(&self) -> usize {
72
518
        self.size
73
518
    }
74
75
68
    pub fn map<T1, F: FnOnce(T) -> T1>(self, f: F) -> Message<T1> {
76
68
        Message::new(self.size(), f(self.into_inner()))
77
68
    }
78
}
79
80
pub trait FromBytes<'a> {
81
    type Output: Sized;
82
83
    fn from_bytes(slice: &'a [u8]) -> Result<Message<Self::Output>>;
84
    //fn copy_to_slice(&self, out_slice: &mut [u8]);
85
}
86
87
pub trait FromBytesWithOffsets<'a>: FromBytes<'a> {
88
    type Offsets: Sized;
89
90
    fn from_bytes_with_offsets(slice: &'a [u8]) -> Result<Message<(Self::Output, Self::Offsets)>>;
91
}
92
93
pub trait WriteTo {
94
    type Input<'a>: Sized;
95
96
    fn write_to<W: std::io::Write>(input: &Self::Input<'_>, out: W) -> Result<()>;
97
}
98
99
pub trait ShapeAndWrite {
100
    fn shape_and_write<W: std::io::Write>(self, out: W) -> Result<()>;
101
}
102
103
#[cfg(feature = "tokio")]
104
pub trait ShapeAndWriteAsync {
105
    fn shape_and_write_async<W: tokio::io::AsyncWriteExt + Unpin>(
106
        self,
107
        out: W,
108
    ) -> impl std::future::Future<Output = Result<()>>;
109
}
110
111
#[cfg(feature = "tokio")]
112
pub trait WriteToAsync: WriteTo {
113
    fn write_to_async<W: tokio::io::AsyncWriteExt + Unpin>(
114
        input: &Self::Input<'_>,
115
        out: W,
116
    ) -> impl std::future::Future<Output = Result<()>>;
117
}
118
119
pub trait WriteSelf {
120
    fn write_self<W: std::io::Write>(&self, out: W) -> Result<()>;
121
    fn size(&self) -> Result<usize>;
122
}
123
124
#[cfg(feature = "tokio")]
125
pub trait WriteSelfAsync {
126
    fn write_self_async<W: tokio::io::AsyncWriteExt + Unpin>(
127
        &self,
128
        out: W,
129
    ) -> impl std::future::Future<Output = Result<()>>;
130
}
131
132
pub trait FromBytesWithHeader<'a, H> {
133
    type Output: Sized;
134
135
    fn from_bytes_with_header(slice: &'a [u8], header: &H) -> Result<Message<Self::Output>>;
136
}
137
138
pub trait WriteToWithHeader<H> {
139
    type Input<'a>: Sized;
140
141
    fn write_to_with_header<W: std::io::Write>(input: &Self::Input<'_>, header: &H, out: W) -> Result<()>;
142
}
143
144
pub trait ShapeHeader<H> {
145
    fn shape_header(&self, header: &mut H) -> Result<()>;
146
}
147
148
impl<H, T: WriteSelf> ShapeHeader<H> for T {
149
0
    fn shape_header(&self, _: &mut H) -> Result<()> {
150
0
        Ok(())
151
0
    }
152
}
153
154
#[cfg(feature = "tokio")]
155
pub trait WriteToWithHeaderAsync<H>: WriteToWithHeader<H> {
156
    fn write_to_with_header_async<W: tokio::io::AsyncWriteExt + Unpin>(
157
        input: &Self::Input<'_>,
158
        header: &H,
159
        out: W,
160
    ) -> impl std::future::Future<Output = Result<()>>;
161
}
162
163
impl<'a, T: WriteTo<Input<'a> = T>> WriteSelf for T {
164
8
    fn write_self<W: std::io::Write>(&self, out: W) -> Result<()> {
165
8
        T::write_to(self, out)
166
8
    }
167
168
4
    fn size(&self) -> Result<usize> {
169
4
        crate::message::util::size_of(self)
170
4
    }
171
}
172
173
#[cfg(feature = "tokio")]
174
impl<T> WriteSelfAsync for T
175
where
176
    for<'a> T: WriteToAsync<Input<'a> = T>,
177
{
178
7
    async fn write_self_async<W: tokio::io::AsyncWriteExt + Unpin>(&self, out: W) -> Result<()> {
179
7
        T::write_to_async(self, out).await
180
7
    }
181
}
182
183
impl<H, T: WriteSelf> WriteToWithHeader<H> for T {
184
    type Input<'b> = T;
185
186
2
    fn write_to_with_header<W: std::io::Write>(input: &Self::Input<'_>, _: &H, out: W) -> Result<()> {
187
2
        input.write_self(out)
188
2
    }
189
}
190
191
#[cfg(feature = "tokio")]
192
impl<H, T: WriteSelf + WriteSelfAsync> WriteToWithHeaderAsync<H> for T {
193
2
    fn write_to_with_header_async<W: tokio::io::AsyncWriteExt + Unpin>(
194
2
        input: &Self::Input<'_>,
195
2
        _: &H,
196
2
        out: W,
197
2
    ) -> impl std::future::Future<Output = Result<()>> {
198
2
        input.write_self_async(out)
199
2
    }
200
}
201
202
impl<'a, H, T: FromBytes<'a>> FromBytesWithHeader<'a, H> for T {
203
    type Output = T::Output;
204
205
0
    fn from_bytes_with_header(slice: &'a [u8], _: &H) -> Result<Message<Self::Output>> {
206
0
        T::from_bytes(slice)
207
0
    }
208
}